/*
 * server.c
 *
 *  Created on: 2014-8-17
 *      Author: liu
 */
#include "camer.h"
#include "encode.h"
#include "server.h"
#include <pthread.h>

int socket_init(own_socket *args);

void setnonblocking(int sock) {
	int opts;
	opts = fcntl(sock, F_GETFL);
	if (opts < 0) {
		perror("fcntl(sock,GETFL)");
		exit(1);
	}
	opts = opts | O_NONBLOCK;
	if (fcntl(sock, F_SETFL, opts) < 0) {
		perror("fcntl(sock,SETFL,opts)");
		exit(errno);
	}

//	opts = fcntl(sock, F_GETFL);
//	if (opts & O_NONBLOCK)
//	{
//		printf("set nonblock successful!\n");
//	}
//	else
//	{
//		printf("set nonblock failed!\n");
//	}

}

int socket_init(own_socket *args) {
	args->listenfd = socket(AF_INET, SOCK_STREAM, 0);
	memset(&(args->serveraddr), 0, sizeof(args->serveraddr));
	args->serveraddr.sin_family = AF_INET;
	//inet_aton(args->dist_addr, &(args->serveraddr.sin_addr)); //htons(portnumber);
	args->serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	args->serveraddr.sin_port = htons(args->portnumber);
	bind(args->listenfd, (struct sockaddr *) &(args->serveraddr),
			sizeof(args->serveraddr));
	listen(args->listenfd, LISTENQ);
	args->epfd = epoll_create(256);
	args->ev.data.fd = args->listenfd;
	args->ev.events = EPOLLIN;
	epoll_ctl(args->epfd, EPOLL_CTL_ADD, args->listenfd, &(args->ev));

	return 0;
}

int stop_signal;

void Stop(int signo) {
	printf("\nloops! stop!!!\n");
	stop_signal = 1;
}

int new_connect_process(own_socket *sock) {
	sock->connfd = accept(sock->listenfd,
			(struct sockaddr *) &(sock->clientaddr), &(sock->clilen));
	if (sock->connfd < 0) {
		perror("connfd<0");
		exit(1);
	}
	setnonblocking(sock->connfd);
	char *str = inet_ntoa(sock->clientaddr.sin_addr);
	printf("accapt a connection from %s \n", str);
	//设置用于读操作的文件描述符
	sock->ev.data.fd = sock->connfd;
	//设置用于注测的读操作事件
	sock->ev.events = EPOLLIN | EPOLLOUT;
	//注册ev
	epoll_ctl(sock->epfd, EPOLL_CTL_ADD, sock->connfd, &(sock->ev));

	return 0;
}

int in_data_process(own_socket *sock, int i) {
	int n;
//	char line[MAXLINE + 1];
//	printf("EPOLLIN\n");
//	printf("recv front...\n");
	if ((n = recv(sock->events[i].data.fd, sock->car_control, 4, 0)) < 0) {
		if (errno == ECONNRESET) {
			printf("ECONNRESET close the socket : %d\n",
					sock->events[i].data.fd);
			close(sock->events[i].data.fd);
			sock->ev.data.fd = sock->events[i].data.fd;
			epoll_ctl(sock->epfd, EPOLL_CTL_DEL, sock->sockfd, &(sock->ev)); //从监听队列删除
			printf("delete complete!\n");
			sock->events[i].data.fd = -1;
			return -1;
		} else {
			printf("readline error\n");
			return -1;
		}
	} else if (n == 0) {
		printf("close the socket : %d\n", sock->events[i].data.fd);
		close(sock->events[i].data.fd);
		sock->events[i].data.fd = -1;
		return -1;
	} else {
//		line[n] = '\0';
	}

//	printf("recv %d\n", line[0]);


	return 0;
}

void control_the_car(char *data)
{
	while(stop_signal != 1)
	{
		switch (data[0]) {
	//	case 0:
	//		system("car_i2c --car_ctrl -s");
	//		break;
		case 1:
			system("./car_i2c --car_ctrl -g");
			break;
		case 2:
			system("./car_i2c --car_ctrl -l");
			break;
		case 4:
			system("./car_i2c --car_ctrl -r");
			break;
		case 8:
			system("./car_i2c --car_ctrl -b");
			break;
		default:
			break;
		}
	}
//	data[0] = 0;
}

inline int send_data(int fd, uint8_t* data, int size) {
	int data_size = size;
	send(fd, &data_size, sizeof(int), 0);
	return send(fd, data, size, 0);
}

void encode_data(own_socket *sock, int i, uint8_t *poutbuf, Encode *encode,
		Camera *camera_s) {
	static int pts = 0;
	av_init_packet(&encode->pkt);
	encode->pkt.data = NULL; // packet data will be allocated by the encoder
	encode->pkt.size = 0;
	while (read_frame(camera_s, encode->src_data[0]));//util the data is prepared
	sws_scale(encode->sws_ctx, (const uint8_t * const *) (encode->src_data),
			encode->src_linesize, 0, encode->pCodecCtx->height,
			encode->picture->data, encode->picture->linesize);
	//PTS
	encode->picture->pts = pts++;
	int got_picture = 0;
	//编码
	//				printf("编码开始\n");
	int ret = avcodec_encode_video2(encode->pCodecCtx, &encode->pkt,
			encode->picture, &got_picture);
	//				printf("编码完成\n");
	if (ret < 0) {
		printf("编码错误！\n");
		return ;
	}
	if (got_picture == 1) {
		//printf("编码成功1帧！\n");
//		int poutbuf_size;
//		int a = av_bitstream_filter_filter(encode->bsfc, encode->pCodecCtx,
//		NULL, &poutbuf, &poutbuf_size, encode->pkt.data, encode->pkt.size, 0);
//		if (a < 0) {
//			fprintf(stderr, "bitstream_filter failed!\n");
//		}
		//printf("send size %d\n", encode->pkt.size);
		send_data(sock->events[i].data.fd, encode->pkt.data, encode->pkt.size);
		av_free_packet(&encode->pkt);
	}
}

int main(int argc, char* argv[]) {
	signal(SIGINT, Stop);
	int i;
	pthread_t thread;
//	int pts = 0;

	own_socket *sock;
	uint8_t *poutbuf = NULL;
	sock = (own_socket *) malloc(sizeof(own_socket));
	bzero(sock, sizeof(own_socket));

	sock->portnumber = 4000;
	printf("listen port: %d\n", (sock->portnumber));

	Encode ecd, *encode;
	encode = &ecd;
	Camera *camera_s, cam;
	camera_s = &cam;

	camera_s = calloc_camera();
	camera_s->width = 320;
	camera_s->height = 240;
	camera_s->type = V4L2_PIX_FMT_YUYV;
	//	sleep(1);
	encode->in_w = camera_s->width;
	encode->in_h = camera_s->height;	//宽高
//		int i;
//	encode->out_file = "src01.h264";					//输出文件路径

//	FILE* tmp_file_fd = fopen("tmp", "rb");

	captureInit(camera_s);
	ffmpeg_init(encode);
	socket_init(sock);
	pthread_create(&thread, NULL, control_the_car, sock->car_control);

	for (; stop_signal != 1;) {
		sock->nfds = epoll_wait(sock->epfd, sock->events, 20, 500);
		//处理所发生的所有事件
		for (i = 0; i < sock->nfds; ++i) {
			if (sock->events[i].data.fd == sock->listenfd) { //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口，建立新的连接。
				new_connect_process(sock);
			}else if (sock->events[i].events & EPOLLIN) { //如果是已经连接的用户，并且收到数据，那么进行读入。
//				if (sock->events[i].data.fd == -1) {
//					continue;
//				} //连接关闭时会触发输入条件
//				if (-1 == in_data_process(sock, i)) {
//					continue;
//				}
				in_data_process(sock, i);
//				sock->ev.data.fd = sock->events[i].data.fd;
//				sock->ev.events = EPOLLOUT;
//				epoll_ctl(sock->epfd, EPOLL_CTL_MOD, sock->events[i].data.fd,
//						&(sock->ev));
			} else if (sock->events[i].events & EPOLLOUT) { // 如果有数据发送
				encode_data(sock, i, poutbuf, encode, camera_s);

//				sock->ev.data.fd = sock->events[i].data.fd;
//				sock->ev.events = EPOLLIN | EPOLLOUT;
//				epoll_ctl(sock->epfd, EPOLL_CTL_MOD, sock->events[i].data.fd,
//						&(sock->ev));
			}
//			control_the_car(sock->car_control);
		}
	}

	printf("flush working...\n");
	ffmpeg_encode_end(encode);
	stop_capturing(camera_s);
	free(sock);
//		fclose(tmp_file_fd);
	return 0;
}
